// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: GPL-3.0-or-later

package xyz.apiote.bimba.czwek.settings.feeds

import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.util.Log
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import com.github.jershell.kbson.KBson
import kotlinx.serialization.Serializable
import xyz.apiote.bimba.czwek.data.settings.SettingsRepository
import xyz.apiote.bimba.czwek.data.sources.Server
import xyz.apiote.bimba.czwek.repo.FeedInfo
import xyz.apiote.bimba.czwek.repo.FeedInfo.Companion.ID_GEOCODING
import xyz.apiote.bimba.czwek.repo.FeedInfo.Companion.ID_TRANSITOUS
import xyz.apiote.bimba.czwek.repo.FeedInfoPrev
import xyz.apiote.fruchtfleisch.Reader
import java.io.File

@Serializable
@OptIn(ExperimentalStdlibApi::class)
data class FeedsSettings(
	val settings: Map<String, FeedSettings>,
	val transitous: FeedSettings?,
	val geocoding: FeedSettings?
) {
	fun activeFeedsCount() = settings.count { it.value.enabled && it.value.useOnline }
	fun activeFeedsCountAll() =
		activeFeedsCount() + if (transitous?.enabled == true && transitous.useOnline == true) {
			1
		} else {
			0
		}

	fun activeFeeds() = settings.filter { it.value.enabled && it.value.useOnline }.keys
	fun getBimbaSelection() = activeFeeds().joinToString(",")
	fun bimbaEnabled() = activeFeeds().isNotEmpty()
	fun ids(): Set<String> {
		return if (transitous?.enabled == true && transitous.useOnline == true) {
			activeFeeds().plus(ID_TRANSITOUS)
		} else {
			activeFeeds()
		}
	}

	operator fun get(id: String): FeedSettings? {
		return when (id) {
			ID_TRANSITOUS -> transitous
			ID_GEOCODING -> geocoding
			else -> settings[id]
		}
	}

	fun with(id: String, settings: FeedSettings): FeedsSettings {
		return when (id) {
			ID_TRANSITOUS -> FeedsSettings(this.settings, settings, geocoding)
			ID_GEOCODING -> FeedsSettings(this.settings, transitous, settings)
			else -> FeedsSettings(this.settings.plus(Pair(id, settings)), transitous, geocoding)
		}
	}

	fun setEnabled(id: String, enabled: Boolean): FeedsSettings {
		val enabledEmptySettings =
			FeedSettings(enabled = enabled, useOnline = false, useOffline = false, autoUpdate = false)
		val settings = when (id) {
			ID_TRANSITOUS -> transitous?.copy(enabled = enabled) ?: enabledEmptySettings
			ID_GEOCODING -> geocoding?.copy(enabled = enabled) ?: enabledEmptySettings
			else -> this.settings[id]?.copy(enabled = enabled) ?: enabledEmptySettings
		}
		return with(id, settings)

	}

	companion object {
		val EMPTY: FeedsSettings = FeedsSettings(emptyMap(), null, null)
		private const val PREFERENCES_NAME = "feeds_settings"

		@Deprecated("load with Server")
		fun load(
			context: Context, apiPath: String = Server.get(context).getSelectedServer().id()
		): FeedsSettings {
			val doc = context.getSharedPreferences(
				PREFERENCES_NAME, MODE_PRIVATE
			).getString(apiPath, null)
			return doc?.let { KBson().load(serializer(), doc.hexToByteArray()) } ?: FeedsSettings(
				emptyMap(), null, null
			)
		}

		@Deprecated("load with Server")
		fun clear(context: Context, apiPath: String = Server.get(context).getSelectedServer().id()) {
			val doc = KBson().dump(serializer(), EMPTY).toHexString()
			context.getSharedPreferences(
				PREFERENCES_NAME, MODE_PRIVATE
			).edit {
				putString(apiPath, doc)
			}
		}
	}
}

@Serializable
data class FeedSettings(
	val enabled: Boolean, val useOnline: Boolean, val useOffline: Boolean = false, val autoUpdate: Boolean = false
)

fun migrateFeedsSettings(context: Context, server: Server = Server.get(context)) {
	if (server.traffic == null) {
		Log.w("migrateFeedsSetting", "server.traffic is null, not migrating")
		return
	}

	val apiPath = server.getSelectedServer().id()
	val shp = context.getSharedPreferences(apiPath, MODE_PRIVATE)
	if (!shp.all.isEmpty()) {
		val settings = mutableMapOf<String, FeedSettings>()
		var transitous: FeedSettings? = null
		shp.all.forEach { (feedID, enabled) ->
			if (enabled as Boolean) {
				if (feedID != ID_TRANSITOUS) {
					settings[feedID] =
						FeedSettings(enabled = true, useOnline = true, useOffline = false, autoUpdate = false)
				} else {
					transitous =
						FeedSettings(enabled = true, useOnline = true, useOffline = false, autoUpdate = false)
				}
			}
		}
		shp.edit {
			clear()
		}
		SettingsRepository().saveFeedsSettings(FeedsSettings(settings, transitous, null), context)
		return
	}

	@Suppress("DEPRECATION") val feedsSettings = FeedsSettings.load(context)
	if (feedsSettings.settings.isNotEmpty()) {
		var transitous = feedsSettings.settings[ID_TRANSITOUS]
		val settings = feedsSettings.settings.minus(ID_TRANSITOUS)
		SettingsRepository().saveFeedsSettings(FeedsSettings(settings, transitous, null), context)
		@Suppress("DEPRECATION")
		FeedsSettings.clear(context)
	}
}

fun migrateGeocodingSettings(context: Context) {
	val preferences = PreferenceManager.getDefaultSharedPreferences(context)
	val autoUpdate = preferences.getBoolean("autoupdate_cities_list", false)

	preferences.edit {
		remove("autoupdate_cities_list")
	}

	if (autoUpdate == false) {
		return
	}

	val repo = SettingsRepository()
	val feedsSettings = repo.getAllFeeds(context)
	val geocoding =
		feedsSettings.geocoding?.copy(enabled = true, useOffline = true, autoUpdate = true)
			?: FeedSettings(enabled = true, useOnline = false, useOffline = true, autoUpdate = true)
	repo.saveFeedsSettings(feedsSettings.with(ID_GEOCODING, geocoding), context)
}

fun migrateFeedInfoCache(context: Context) {
	val file = File(context.filesDir, Server.get(context).getSelectedServer().id())
	if (!file.exists()) {
		return
	}

	val stream = file.inputStream()
	val feeds = mutableMapOf<String, FeedInfo>()
	val n = Reader(stream).readUInt().toULong().toInt()
	repeat(n) {
		val feed = FeedInfoPrev.unmarshal(stream)
		feeds[feed.id] = feed
	}

	val repo = SettingsRepository()
	repo.saveFeedInfos(feeds, context)
}
